package com.wdhcr.osspolicy.config;

import com.wdhcr.osspolicy.annotation.OssConverter;
import com.wdhcr.osspolicy.component.OssComponent;
import com.wdhcr.osspolicy.mode.R;
import com.wdhcr.osspolicy.utils.ReflectUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import java.lang.reflect.Field;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

@Slf4j
@RestControllerAdvice(basePackages = "com.wdhcr")
public class ResponseBodyConfig implements ResponseBodyAdvice {

    @Autowired
    private OssComponent ossComponent;

    @Autowired
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;


    @Override
    public boolean supports(MethodParameter returnType, Class converterType) {
        return true;
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {

        long start = System.currentTimeMillis();

        if (body instanceof R) {
            R result = (R) body;
            Object data = result.getData();
            Map<Field,Object> fields = new HashMap<>();
            ReflectUtil.getAllFields(data,fields);
            ArrayList<CompletableFuture<Void>> futures = new ArrayList<>();
            for (Field field : fields.keySet()) {
                OssConverter annotation = field.getAnnotation(OssConverter.class);
                if (annotation != null) {
                    CompletableFuture<Void> future = CompletableFuture.runAsync(() -> setImageUrlWithOssUrl(field, fields),threadPoolTaskExecutor);
                    futures.add(future);
                }
            }
            CompletableFuture[] completableFutures = new CompletableFuture[futures.size()];
            try {
                CompletableFuture.allOf(futures.toArray(completableFutures)).get();
            } catch (InterruptedException | ExecutionException e) {
                e.printStackTrace();
            }
        }
        long end = System.currentTimeMillis();

        System.err.println("总计用时：" + ((end - start)));
        return body;
    }

    private void setImageUrlWithOssUrl(Field field, Map<Field, Object> fields) {

        Object value = null;
        try {
            field.setAccessible(true);
            value = field.get(fields.get(field));
            if (value != null) {
                String url = ossComponent.getUrl(value.toString());
                field.set(fields.get(field), url);
            }
        } catch (Exception e) {
            log.error("更新返回体中oss地址的字段异常,值为：{}", value);
        }

    }

}
